﻿using System;
using System.Linq;
using System.Web;
using Autofac;
using Autofac.Integration.Mvc;
using Zoo.Cat.Application.Authentication;
using Zoo.Cat.Application.Jobseekers;
using Zoo.Cat.Application.Polls;
using Zoo.Infrastructure;
using Zoo.Infrastructure.Caching;
using Zoo.Infrastructure.Data;
using Zoo.Infrastructure.Data.Core;
using Zoo.Infrastructure.Events;
using Zoo.Infrastructure.Fakes;
using Zoo.Infrastructure.IoC;
using Zoo.Infrastructure.IoC.DependencyManagement;
using Zoo.Web.Framework.Mvc.Routes;
using Zoo.Web.Framework.Themes;
using Zoo.Cat.Application.Security;
using Zoo.Cat.Application.Jobs;
using Zoo.Cat.Application.Links;

namespace Zoo.Cat.Web.Framework.Infrastructure {
    public class DependencyRegistrar : IDependencyRegistrar {

        public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder) {
            //HTTP context and other related stuff
            builder.Register(c =>
                //register FakeHttpContext when HttpContext is not available
                HttpContext.Current != null ?
                (new HttpContextWrapper(HttpContext.Current) as HttpContextBase) :
                (new FakeHttpContext("~/") as HttpContextBase))
                .As<HttpContextBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Request)
                .As<HttpRequestBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Response)
                .As<HttpResponseBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Server)
                .As<HttpServerUtilityBase>()
                .InstancePerHttpRequest();
            builder.Register(c => c.Resolve<HttpContextBase>().Session)
                .As<HttpSessionStateBase>()
                .InstancePerHttpRequest();

            //web helper
            builder.RegisterType<WebHelper>().As<IWebHelper>().InstancePerHttpRequest();

            //controllers
            builder.RegisterControllers(typeFinder.GetAssemblies().ToArray());

            //data layer
            var dataSettingsManager = new DataSettingsManager();
            var dataProviderSettings = dataSettingsManager.LoadSettings();
            builder.Register(c => dataSettingsManager.LoadSettings()).As<DataSettings>();
            builder.Register(x => new EfDataProviderManager(x.Resolve<DataSettings>())).As<BaseDataProviderManager>().InstancePerDependency();


            builder.Register(x => (IEfDataProvider)x.Resolve<BaseDataProviderManager>().LoadDataProvider()).As<IDataProvider>().InstancePerDependency();
            builder.Register(x => (IEfDataProvider)x.Resolve<BaseDataProviderManager>().LoadDataProvider()).As<IEfDataProvider>().InstancePerDependency();

            if (dataProviderSettings != null && dataProviderSettings.IsValid()) {
                var efDataProviderManager = new EfDataProviderManager(dataSettingsManager.LoadSettings());
                var dataProvider = (IEfDataProvider)efDataProviderManager.LoadDataProvider();
                dataProvider.InitConnectionFactory();

                builder.Register<IDbContext>(c => new ZooObjectContext(dataProviderSettings.DataConnectionString)).InstancePerHttpRequest();
            }
            else {
                builder.Register<IDbContext>(c => new ZooObjectContext(dataSettingsManager.LoadSettings().DataConnectionString)).InstancePerHttpRequest();
            }


            builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>)).InstancePerHttpRequest();

            //plugins
            //builder.RegisterType<PluginFinder>().As<IPluginFinder>().InstancePerHttpRequest();

            //cache manager
            builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
            builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerHttpRequest();


            //work context
            builder.RegisterType<WorkContext>().As<IWorkContext>().InstancePerHttpRequest();

            //services
            builder.RegisterType<PollService>().As<IPollService>().InstancePerHttpRequest();
            builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().SingleInstance();


            builder.RegisterType<ThemeProvider>().As<IThemeProvider>().InstancePerHttpRequest();
            builder.RegisterType<ThemeContext>().As<IThemeContext>().InstancePerHttpRequest();

            builder.RegisterType<JobService>().As<IJobService>().InstancePerHttpRequest();
            builder.RegisterType<JobseekerService>().As<IJobseekerService>().InstancePerHttpRequest();
            builder.RegisterType<JobseekerRegistrationService>().As<IJobseekerRegistrationService>().InstancePerHttpRequest();

            builder.RegisterType<FormsAuthenticationService>().As<IAuthenticationService>().InstancePerHttpRequest();
            builder.RegisterType<EncryptionService>().As<IEncryptionService>().InstancePerHttpRequest();


            builder.RegisterType<LinkService>().As<ILinkService>().InstancePerHttpRequest();

            //builder.RegisterType<>().As<I>().InstancePerHttpRequest();




            //Register event consumers
            var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList();
            foreach (var consumer in consumers) {
                builder.RegisterType(consumer)
                    .As(consumer.FindInterfaces((type, criteria) => {
                        var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
                        return isMatch;
                    }, typeof(IConsumer<>)))
                    .InstancePerHttpRequest();
            }
            builder.RegisterType<EventPublisher>().As<IEventPublisher>().SingleInstance();
            builder.RegisterType<SubscriptionService>().As<ISubscriptionService>().SingleInstance();
        }

        public int Order {
            get { return 0; }
        }
    }


}
